<template>
  <table
    cellspacing="0"
    cellpadding="0"
    border="0"
    :style="styles"
  >
    <colgroup>
      <col
        v-for="(column, index) in columns"
        :width="setCellWidth(column)"
      >
      <col
        v-if="$parent.showVerticalScrollBar"
        :width="$parent.scrollBarWidth"
      >
    </colgroup>
    <thead>
      <tr v-for="(cols, rowIndex) in headRows">
        <th
          v-for="(column, index) in cols"
          :colspan="column.colSpan"
          :rowspan="column.rowSpan"
          :class="alignCls(column)"
        >
          <div :class="cellClasses(column)">
            <template v-if="column.type === 'expand'">
              <span v-if="!column.renderHeader">{{ column.title || '' }}</span>
              <render-header
                v-else
                :render="column.renderHeader"
                :column="column"
                :index="index"
              />
            </template>
            <template v-else-if="column.type === 'selection'">
              <Checkbox
                :model-value="isSelectAll"
                :disabled="isSelectDisabled"
                @on-change="selectAll"
              />
            </template>
            <template v-else>
              <span
                v-if="!column.renderHeader"
                :class="{[prefixCls + '-cell-sort']: column.sortable}"
                @click="column.sortable && handleSortByHead(getColumn(rowIndex, index)._index)"
              >{{ column.title || '#' }}</span>
              <render-header
                v-else
                :render="column.renderHeader"
                :column="column"
                :index="index"
              />
              {{ ' ' }}
              <span
                v-if="column.sortable"
                :class="[prefixCls + '-sort']"
              >
                <i
                  class="ion ion-md-arrow-dropup"
                  :class="{on: getColumn(rowIndex, index)._sortType === 'asc'}"
                  @click="handleSort(getColumn(rowIndex, index)._index, 'asc')"
                />
                <i
                  class="ion ion-md-arrow-dropdown"
                  :class="{on: getColumn(rowIndex, index)._sortType === 'desc'}"
                  @click="handleSort(getColumn(rowIndex, index)._index, 'desc')"
                />
              </span>
              {{ ' ' }}
              <Poptip
                v-if="isPopperShow(column)"
                :model-value="getColumn(rowIndex, index)._filterVisible"
                placement="bottom"
                popper-class="ivu-table-popper"
                transfer
                :capture="false"
                @update:model-value="getColumn(rowIndex, index)._filterVisible = $event"
                @on-popper-hide="handleFilterHide(getColumn(rowIndex, index)._index)"
              >
                <span :class="[prefixCls + '-filter']">
                  <i
                    class="ion ion-ios-funnel"
                    :class="{on: getColumn(rowIndex, index)._isFiltered}"
                  />
                </span>

                <template
                  v-if="getColumn(rowIndex, index)._filterMultiple"
                  #content
                >
                  <div
                    :class="[prefixCls + '-filter-list']"
                  >
                    <div :class="[prefixCls + '-filter-list-item']">
                      <CheckboxGroup
                        :model-value="getColumn(rowIndex, index)._filterChecked"
                        @update:model-value="getColumn(rowIndex, index)._filterChecked = $event"
                      >
                        <Checkbox
                          v-for="(item, index) in column.filters"
                          :key="index"
                          :label="item.value"
                        >
                          {{ item.label }}
                        </Checkbox>
                      </CheckboxGroup>
                    </div>
                    <div :class="[prefixCls + '-filter-footer']">
                      <VButton
                        type="text"
                        size="small"
                        :disabled="!getColumn(rowIndex, index)._filterChecked.length"
                        @click.native="handleFilter(getColumn(rowIndex, index)._index)"
                      >
                        {{ t('i.table.confirmFilter') }}
                      </VButton>
                      <VButton
                        type="text"
                        size="small"
                        @click.native="handleReset(getColumn(rowIndex, index)._index)"
                      >
                        {{ t('i.table.resetFilter') }}
                      </VButton>
                    </div>
                  </div>
                </template>
                <template
                  v-else
                  #content
                >
                  <div
                    :class="[prefixCls + '-filter-list']"
                  >
                    <ul :class="[prefixCls + '-filter-list-single']">
                      <li
                        :class="itemAllClasses(getColumn(rowIndex, index))"
                        @click="handleReset(getColumn(rowIndex, index)._index)"
                      >
                        {{ t('i.table.clearFilter') }}
                      </li>
                      <li
                        v-for="item in column.filters"
                        :class="itemClasses(getColumn(rowIndex, index), item)"
                        @click="handleSelect(getColumn(rowIndex, index)._index, item.value)"
                      >
                        {{ item.label }}
                      </li>
                    </ul>
                  </div>
                </template>
              </Poptip>
            </template>
          </div>
          <div
            v-if="column.resizable"
            class="ivu-table-header-resizable"
            @mousedown="handleMouseDown(column, $event)"
            @mousemove="handleMouseMove(column, $event)"
            @mouseout="handleMouseOut"
          />
        </th>

        <th
          v-if="$parent.showVerticalScrollBar && rowIndex===0"
          :class="scrollBarCellClass()"
          :rowspan="headRows.length"
        />
      </tr>
    </thead>
  </table>
</template>
<script>
import CheckboxGroup from './checkbox-group.vue'
import Checkbox from './checkbox.vue'
import Poptip from './poptip.vue'
import VButton from './button.vue'
import renderHeader from './header'
import Mixin from '../mixins/table'
import Locale from '../mixins/locale'

export default {
  name: 'TableHead',
  components: { CheckboxGroup, Checkbox, Poptip, VButton, renderHeader },
  mixins: [Mixin, Locale],
  props: {
    prefixCls: String,
    styleObject: Object,
    columns: Array,
    objData: Object,
    data: Array, // rebuildData
    columnsWidth: Object,
    fixed: {
      type: [Boolean, String],
      default: false
    },
    columnRows: Array,
    fixedColumnRows: Array
  },
  data () {
    return {
      draggingColumn: null,
      dragging: false,
      dragState: {}
    }
  },
  computed: {
    styles () {
      const style = Object.assign({}, this.styleObject)
      const width = parseInt(this.styleObject.width)
      style.width = `${width}px`
      return style
    },
    isSelectAll () {
      let isSelectAll = true
      if (!this.data.length) isSelectAll = false

      // 全部disabled且全false，#1751
      let isAllDisabledAndUnSelected = true

      for (const i in this.objData) {
        const objData = this.objData[i]
        if (!objData._isChecked && !objData._isDisabled) {
          isSelectAll = false
          break
        } else if (objData.children && objData.children.length) {
          isSelectAll = this.isChildrenSelected(objData, isSelectAll)
        }
        if (!(objData._isDisabled && !objData._isChecked)) {
          isAllDisabledAndUnSelected = false
        } else if (objData.children && objData.children.length) {
          isAllDisabledAndUnSelected = this.isChildrenAllDisabledAndUnSelected(objData, isAllDisabledAndUnSelected)
        }
      }
      if (isAllDisabledAndUnSelected) isSelectAll = false

      return isSelectAll
    },
    headRows () {
      const isGroup = this.columnRows.length > 1
      if (isGroup) {
        return this.fixed ? this.fixedColumnRows : this.columnRows
      } else {
        return [this.columns]
      }
    },
    isSelectDisabled () {
      let isSelectDisabled = true
      if (this.data.length) {
        for (const i in this.objData) {
          const objData = this.objData[i]
          if (!objData._isDisabled) {
            isSelectDisabled = false
          } else if (objData.children && objData.children.length) {
            isSelectDisabled = this.isChildrenDisabled(objData, isSelectDisabled)
          }
        }
      }
      return isSelectDisabled
    }
  },
  methods: {
    cellClasses (column) {
      return [
                    `${this.prefixCls}-cell`,
                    {
                      [`${this.prefixCls}-hidden`]: !this.fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right'),
                      [`${this.prefixCls}-cell-with-selection`]: column.type === 'selection'
                    }
      ]
    },
    scrollBarCellClass () {
      let hasRightFixed = false
      for (const i in this.headRows) {
        for (const j in this.headRows[i]) {
          if (this.headRows[i][j].fixed === 'right') {
            hasRightFixed = true
            break
          }
          if (hasRightFixed) break
        }
      }
      return [
        {
          [`${this.prefixCls}-hidden`]: hasRightFixed
        }
      ]
    },
    itemClasses (column, item) {
      return [
                    `${this.prefixCls}-filter-select-item`,
                    {
                      [`${this.prefixCls}-filter-select-item-selected`]: column._filterChecked[0] === item.value
                    }
      ]
    },
    itemAllClasses (column) {
      return [
                    `${this.prefixCls}-filter-select-item`,
                    {
                      [`${this.prefixCls}-filter-select-item-selected`]: !column._filterChecked.length
                    }
      ]
    },
    selectAll () {
      const status = !this.isSelectAll
      this.$parent.selectAll(status)
    },
    handleSort (index, type) {
      // 在固定列时，寻找正确的 index #5580
      const column = this.columns.find(item => item._index === index)
      const _index = column._index

      if (column._sortType === type) {
        type = 'normal'
      }
      this.$parent.handleSort(_index, type)
    },
    handleSortByHead (index) {
      // 在固定列时，寻找正确的 index #5580
      const column = this.columns.find(item => item._index === index)
      if (column.sortable) {
        const type = column._sortType
        if (type === 'normal') {
          this.handleSort(index, 'asc')
        } else if (type === 'asc') {
          this.handleSort(index, 'desc')
        } else {
          this.handleSort(index, 'normal')
        }
      }
    },
    handleFilter (index) {
      this.$parent.handleFilter(index)
    },
    handleSelect (index, value) {
      this.$parent.handleFilterSelect(index, value)
    },
    handleReset (index) {
      this.$parent.handleFilterReset(index)
    },
    handleFilterHide (index) {
      this.$parent.handleFilterHide(index)
    },
    // 因为表头嵌套不是深拷贝，所以没有 _ 开头的方法，在 isGroup 下用此列
    getColumn (rowIndex, index) {
      const isGroup = this.columnRows.length > 1

      if (isGroup) {
        const id = this.headRows[rowIndex][index].__id
        return this.columns.filter(item => item.__id === id)[0]
      } else {
        return this.headRows[rowIndex][index]
      }
    },
    handleMouseDown (column, event) {
      if (this.$isServer) return

      if (this.draggingColumn) {
        this.dragging = true

        const table = this.$parent
        const tableEl = table.$el
        const tableLeft = tableEl.getBoundingClientRect().left
        const columnEl = this.$el.querySelector(`th.ivu-table-column-${column.__id}`)
        const columnRect = columnEl.getBoundingClientRect()
        const minLeft = columnRect.left - tableLeft + 30

        table.showResizeLine = true

        this.dragState = {
          startMouseLeft: event.clientX,
          startLeft: columnRect.right - tableLeft,
          startColumnLeft: columnRect.left - tableLeft,
          tableLeft
        }

        const resizeProxy = table.$refs.resizeLine
        resizeProxy.style.left = this.dragState.startLeft + 'px'

        document.onselectstart = function () { return false }
        document.ondragstart = function () { return false }

        const handleMouseMove = (event) => {
          const deltaLeft = event.clientX - this.dragState.startMouseLeft
          const proxyLeft = this.dragState.startLeft + deltaLeft

          resizeProxy.style.left = Math.max(minLeft, proxyLeft) + 'px'
        }

        const handleMouseUp = () => {
          if (this.dragging) {
            const {
              startColumnLeft,
              startLeft
            } = this.dragState

            const finalLeft = parseInt(resizeProxy.style.left, 10)
            const columnWidth = finalLeft - startColumnLeft

            const _column = table.columns.find(item => item.__id === column.__id)
            if (_column) _column.width = columnWidth
            table.$emit('on-column-width-resize', _column.width, startLeft - startColumnLeft, column, event)

            document.body.style.cursor = ''
            this.dragging = false
            this.draggingColumn = null
            this.dragState = {}

            table.showResizeLine = false
          }

          document.removeEventListener('mousemove', handleMouseMove)
          document.removeEventListener('mouseup', handleMouseUp)
          document.onselectstart = null
          document.ondragstart = null
        }

        document.addEventListener('mousemove', handleMouseMove)
        document.addEventListener('mouseup', handleMouseUp)
      }
    },
    handleMouseMove (column, event) {
      let target = event.target

      while (target && target.tagName !== 'TH') {
        target = target.parentNode
      }

      if (!column || !column.resizable) return

      if (!this.dragging) {
        const rect = target.getBoundingClientRect()

        const bodyStyle = document.body.style

        if (rect.width > 12 && rect.right - event.pageX < 8) {
          bodyStyle.cursor = 'col-resize'
          this.draggingColumn = column
        } else if (!this.dragging) {
          bodyStyle.cursor = ''
          this.draggingColumn = null
        }
      }
    },
    handleMouseOut () {
      if (this.$isServer) return
      document.body.style.cursor = ''
    },
    isChildrenSelected (objData, isSelectAll) {
      let status = isSelectAll
      if (objData.children && objData.children.length) {
        objData.children.forEach(row => {
          if (!row._isChecked && !row._isDisabled) {
            status = false
          } else if (row.children && row.children.length) {
            status = this.isChildrenSelected(row, status)
          }
        })
      }
      return status
    },
    isChildrenAllDisabledAndUnSelected (objData, isAllDisabledAndUnSelected) {
      let status = isAllDisabledAndUnSelected
      if (objData.children && objData.children.length) {
        objData.children.forEach(row => {
          if (!(row._isDisabled && !row._isChecked)) {
            status = false
          } else if (row.children && row.children.length) {
            status = this.isChildrenAllDisabledAndUnSelected(row, status)
          }
        })
      }
      return status
    },
    isChildrenDisabled (objData, isSelectDisabled) {
      let status = isSelectDisabled
      if (objData.children && objData.children.length) {
        objData.children.forEach(row => {
          if (!row._isDisabled) {
            status = false
          } else if (row.children && row.children.length) {
            status = this.isChildrenDisabled(row, status)
          }
        })
      }
      return status
    }
  }
}
</script>
